package com.nulldev.util.java.swing.vdesktop;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import com.nulldev.util.FinalBypass;
import com.nulldev.util.image.ImageUtil;
import com.nulldev.util.java.DataSet;
import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.java.swing.SwingUtil;
import com.nulldev.util.java.swing.extSwing.lookandfeel.themes.ThemeApplier;
import com.nulldev.util.java.swing.font.FontManager;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.os.BIOSUtil;
import com.nulldev.util.os.CPUUtil;
import com.nulldev.util.os.GPUUtil;
import com.nulldev.util.other.ByteUtils;
import com.nulldev.util.other.CharsetUtil;
import com.nulldev.util.string.StringsUtil;
import com.nulldev.util.sys.process.Process;
import com.nulldev.util.sys.process.ProcessManager;
import com.nulldev.util.threading.legacy.ThreadExecutor;
import com.nulldev.util.uri.URIUtil;
import com.nulldev.util.uri.URIUtil2;
import com.nulldev.util.uri.yt.VideoMeta;
import com.nulldev.util.uri.yt.YouTubeExtractor;
import com.nulldev.util.uri.yt.YtFile;

import sun.swing.SwingUtilities2;

import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;

public class vDesktop extends JFrame {

	private JPanel contentPane;
	private JTextField textField;

	/**
	 * Launch the application.
	 */
	public static void main() {
		SwingUtil.enableAA();
		SwingUtil.enableJSO();
		FontManager.loadSystemSpecificFonts();
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					vDesktop frame = new vDesktop();
					ThemeApplier.applyTheme(frame);
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public vDesktop() {
		setIconImage(Toolkit.getDefaultToolkit().getImage(vDesktop.class.getResource("/com/nulldev/util/java/swing/nullutil_logo.png")));
		setTitle("nullOS.vDesktop");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 772, 429);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));
		
		final BufferedImage img = ImageUtil.createFromColorImg(Color.BLACK, 1, 1);
		final FinalBypass<Integer> prevWidth = new FinalBypass<Integer>(0), prevHeight = new FinalBypass<Integer>(0);
		final FinalBypass<BufferedImage> prevImage = new FinalBypass<BufferedImage>(img);
		JDesktopPane desktopPane = new JDesktopPane() {
            @Override
            protected void paintComponent(final Graphics grphcs) {
            	if (grphcs instanceof Graphics2D) {
            		final Graphics2D g2d = (Graphics2D) grphcs;
            		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            	}
                super.paintComponent(grphcs);
            	if (prevWidth.getObject() != getWidth() || prevHeight.getObject() != getHeight()) {
            		prevWidth.setObject(getWidth());
            		prevHeight.setObject(getHeight());
            		prevImage.setObject(ImageUtil.scale(img, prevWidth.getObject(), prevHeight.getObject()));
            		grphcs.drawImage(prevImage.getObject(), 0, 0, null);
            	}else {
            		grphcs.drawImage(prevImage.getObject(), 0, 0, null);
            	}
                ///grphcs.setColor(Color.WHITE);
                ///grphcs.drawString("VGA Renderer", 5, 15);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(img.getWidth(), img.getHeight());
            }
		};
		desktopPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
		desktopPane.setBorder(null);
		contentPane.add(desktopPane, BorderLayout.CENTER);
		desktopPane.setLayout(null);
		
		JInternalFrame internalFrame = new JInternalFrame("vTerminal");
		internalFrame.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
		internalFrame.setMaximizable(true);
		internalFrame.setIconifiable(true);
		internalFrame.setResizable(true);
		internalFrame.setBounds(12, 12, 533, 250);
		desktopPane.add(internalFrame);
		internalFrame.getContentPane().setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane = new JScrollPane();
		internalFrame.getContentPane().add(scrollPane, BorderLayout.CENTER);
		
		JTextPane textPane = new JTextPane();
		textPane.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
		textPane.setFont(FontManager.getMimeFont(14));
		textPane.setText("nullOS for vDesktop, rc-1.0-8a93fe0a, 1.0, vd-emu-platform");
		textPane.setEditable(false);
		scrollPane.setViewportView(textPane);
		
		ThemeApplier.applyTheme(internalFrame);
		
		JPanel panel = new JPanel();
		internalFrame.getContentPane().add(panel, BorderLayout.SOUTH);
		panel.setLayout(new BorderLayout(0, 0));
		
		textField = new JTextField();
		textField.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
		textField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (textField == null || textField.getText() == null || textField.getText().length() == 0) {
					return;
				}
				final String text = textField.getText();
				textField.setText("");
				processTerminal(text);
			}

			private void processTerminal(final String text) {
				final String[] args = text.split(" ");
				if (isEqualCM(args, 0, "uname")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("uname [arg]" + JVMUtil.lineSep() +
								"  -a - Prints all args" + lineSep() +
								"  -n - Prints OS name" + lineSep() +
								"  -b - Prints OS build" + lineSep() + 
								"  -v - Prints OS version" + lineSep() +
								"  -p - Prints platform information");
						return;
					}else if (isEqualCM(args, 1, "-a")) {
						append("nullOS for vDesktop, rc-1.0-8a93fe0a, 1.0, vd-emu-platform");
						return;
					}else if (isEqualCM(args, 1, "-n")) {
						append("nullOS for vDesktop");
						return;
					}else if (isEqualCM(args, 1, "-b")) {
						append("rc-1.0-8a93fe0a");
						return;
					}else if (isEqualCM(args, 1, "-v")) {
						append("1.0");
						return;
					}else if (isEqualCM(args, 1, "-p")) {
						append("vd-emu-platform");
						return;
					}
				}else if (isEqualCM(args, 0, "random")) {
					append(String.valueOf(Math.random()));
					return;
				}else if (isEqualCM(args, 0, "urandom")) {
					append(new String(MathUtil.randomBytes(ByteUtils.create(256)), CharsetUtil.getCharset()));
					return;
				}else if (isEqualCM(args, 0, "clear")) {
					textPane.setText("");
					return;
				}else if (isEqualCM(args, 0, "lspci")) {
					append("PCI devices: " + lineSep() + "  - 00:00:00 USB Controller." + lineSep() + "  - 00:01:00 VGA driver.");
					return;
				}else if (isEqualCM(args, 0, "lsusb")) {
					append("USB devices: " + lineSep() + "  - 00:00:00 Generic USB Mouse." + lineSep() + "  - 00:01:00 Generic USB Keyboard.");
					return;
				}else if (isEqualCM(args, 0, "rmrfx")) {
					append("Running 'rm --rf /'...");
					ThreadExecutor.execute(new Runnable() {
						
						@Override
						public void run() {
							try {
								Thread.sleep(500L);
							} catch (InterruptedException e) {
							}
							append("rm: Command refused.");
						}
					});
					return;
				}else if (isEqualCM(args, 0, "edit")) {
					final vIDEditor vide = vIDEditor.main();
					vide.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
							RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					desktopPane.add(vide);
					return;
				}else if (isEqualCM(args, 0, "sec-engine")) {
					final vSecEngine vide = vSecEngine.main();
					vide.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
							RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					desktopPane.add(vide);
					return;
				}else if (isEqualCM(args, 0, "ping")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("ping [url]");
						return;
					}
					try {
						final DataSet<Boolean, Long> reachable = URIUtil2.ProxyUtils.accessible(URIUtil.safeCreate(args[1]));
						append("result=" + reachable.getA() + ",timeTaken_MS=" + reachable.getB());
					}catch (Exception e) {
						//e.printStackTrace();
						append("Error occured.");
					}
					return;
				}else if (isEqualCM(args, 0, "query")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("query [cpu/gpu/processes/bios/spotify]");
						return;
					}
					
					if (isEqualCM(args, 1, "cpu")) {
						append(CPUUtil.parse().toString());
						return;
					}else if (isEqualCM(args, 1, "gpu")) {
						append(GPUUtil.parse().toString());
						return;
					}else if (isEqualCM(args, 1, "bios")) {
						append(BIOSUtil.parse().toString());
						return;
					}else if (isEqualCM(args, 1, "processes")) {
						append("Active Processes: " + ProcessManager.parse().size());
						return;
					}else if (isEqualCM(args, 1, "spotify")) {
						ProcessManager.parse();
						for (final Process x : ProcessManager.getProcesses("spotify", "Spotify.exe")) {
							if (!x.isBlank() && x.getTitle().contains(" - ")) {
								append("Spotify Data: " + x.getTitle());
								return;
							}
						}
						append("No spotify processes found.");
						return;
					}
					return;
				}else if (isEqualCM(args, 0, "get-src")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("get-src [url]");
						return;
					}
					try {
						final String src = URIUtil.downloadPage(URIUtil.safeCreate(args[1]));
						final vIDEditor editor = vIDEditor.main(src);
						editor.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(
								RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
						desktopPane.add(editor);
						return;
					}catch (Exception e) {}
					return;
				}else if (isEqualCM(args, 0, "ytd")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("ytd [url]");
						return;
					}
					try {
						final YouTubeExtractor yt = new YouTubeExtractor() {
							
							@Override
							protected void onExtractionComplete(HashMap<Integer, YtFile> ytFiles, VideoMeta videoMeta) {
								append("videoMeta=" + videoMeta);
								for (final YtFile file : ytFiles.values()) {
									append("ytFile=" + file);
								}
							}
						};
						yt.extract(args[1], true, true, false);
//						final YTDownloader2 ytd2 = new YTDownloader2();
//						for (final FmtStreamMap fmt : ytd2.fetchMap(args[1])) {
//							append(fmt.toString());
//						}
						return;
					}catch (Exception e) {}
					return;
				}else if (isEqualCM(args, 0, "shutdown")) {
					if (args.length == 1 || isEqualCM(args, 1, "-h")) {
						append("shutdown [now]");
						return;
					}
					if (isEqualCM(args, 1, "now")) {
						append("Shutting down...");
						ThreadExecutor.execute(new Runnable() {
							
							@Override
							public void run() {
								try {
									Thread.sleep(500L);
								} catch (InterruptedException e) {
								}
								JVMUtil.exit();
							}
						});
						return;
					}
					append("shutdown [now]");
					return;
				}
				append("Unknown command.");
			}
			
			private void append(final String text) {
				if (textPane.getText() == null || textPane.getText().length() == 0) {
					textPane.setText(text);
				}else {
					textPane.setText(textPane.getText() + JVMUtil.lineSep() + text);
				}
			}
			
			private boolean isEqualCM(final String[] args, final int index, final String term) {
				return StringsUtil.isEqualCM(args, index, term);
			}
			
			private String lineSep() {
				return JVMUtil.lineSep();
			}
		});
		panel.add(textField, BorderLayout.CENTER);
		textField.setColumns(10);
		internalFrame.setVisible(true);
	}
}
